﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;

using InfFront.UICore;
using InfFront.InfoViews.Base;

namespace InfFront.InfoViews.WPF
{
    /// <summary>
    /// Interaction logic for SingleEntryFrame.xaml
    /// </summary>
    public partial class SingleEntryFrame : UserControl
    {
        #region Private Variables
        private InfoViewEntry oldDataContext = null;
        private InfoEntryFieldEnumItemConverter enumConverter = null;
        private bool isInCloseableWindow;
        #endregion

        #region Construction/Initialization
        public SingleEntryFrame()
        {
            InitializeComponent();

            enumConverter = new InfoEntryFieldEnumItemConverter();
            IsInCloseableWindow = false;
        }

        public new InfoViewEntry DataContext
        {
            get { return (InfoViewEntry)base.DataContext; }
            set { base.DataContext = value; }
        }

        public override void BeginInit()
        {
            base.BeginInit();
            Resources["editorTemplateSelector"] = new EditorTemplateSelector(this);
        }

        #endregion

        [Browsable(false), DefaultValue(false)]
        public bool IsInCloseableWindow
        {
            get { return isInCloseableWindow; }
            set
            {
                isInCloseableWindow = value;
                CheckButtonsVisibility();
            }
        }

        public event EventHandler CloseButtonClick;

        private void this_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            Rebuild();

            if (oldDataContext != null)
            {
                oldDataContext.CancelEdit();
                oldDataContext.OnRefreshed -= source_OnRefreshed;
            }

            oldDataContext = DataContext;
            if (oldDataContext != null)
            {
                oldDataContext.BeginEdit();
                oldDataContext.OnRefreshed += source_OnRefreshed;
            }

            CheckButtonsVisibility();
        }

        public void Rebuild()
        {
            if (DataContext == null)
            {
                if (oldDataContext != null)
                {
                    using (new InfoViewEntry.FreezeState(oldDataContext))
                    {
                        fieldsControlList.ItemsSource = null;
                        fieldGroupsControlList.ItemsSource = null;
                    }
                }
                return;
            }

            fieldsControlList.ItemsSource = DataContext.UngrouppedEditableFields;
            fieldGroupsControlList.ItemsSource = DataContext.EditGroups;
        }

        private Visibility FromBool(bool visible)
        {
            return visible ? Visibility.Visible : Visibility.Hidden;
        }

        private void CheckButtonsVisibility()
        {
            btnOk.Visibility = FromBool(IsInCloseableWindow);
            btnCancel.Visibility = FromBool(IsInCloseableWindow || DataContext != null && DataContext.NeedsEditBuffer);
            btnApply.Visibility = FromBool(DataContext != null && DataContext.NeedsEditBuffer);
        }

        private void source_OnRefreshed(object sender, EventArgs e)
        {
            Rebuild();
        }

        private void enumComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            var cb = (ComboBox)sender;
            var binding = new Binding("Value");
            binding.Source = cb.DataContext;
            binding.Converter = enumConverter;
            binding.ConverterParameter = cb.DataContext;
            binding.Mode = BindingMode.TwoWay;
            BindingOperations.SetBinding(cb, ComboBox.TextProperty, binding);
        }

        private void Close()
        {
            EventHandler handler = CloseButtonClick;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        private void btnOk_Click(object sender, RoutedEventArgs e)
        {
            DataContext.EndEdit();
            Close();
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            DataContext.CancelEdit();
            Close();
            if (!IsInCloseableWindow) // the frame is not closed, so we continue editing
            {
                DataContext.BeginEdit();
            }
        }

        private void btnApply_Click(object sender, RoutedEventArgs e)
        {
            DataContext.ApplyEdit();
        }

        private void btnSelectReference_Click(object sender, RoutedEventArgs e)
        {
            var field = (InfoViewEntryField)((FrameworkElement)sender).DataContext;
            var wnd = new EntrySelectWindow();
            wnd.Owner = Application.Current.MainWindow;
            Debug.Assert(field.ReferencedField != null);
            if (wnd.Execute(field.ReferencedField.Owner))
            {
                var selectedEntry = wnd.SelectedEntry;
                if (selectedEntry == null)
                    field.Value = null;
                else
                    field.Value = selectedEntry.GetFieldValue(field.ReferencedField);
            }

            e.Handled = true;
        }
    }

    public class EditorTemplateSelector : DataTemplateSelector
    {
        private SingleEntryFrame frame;

        public EditorTemplateSelector(SingleEntryFrame frame)
        {
            this.frame = frame;
        }

        private DataTemplate GetResource(string name)
        {
            return (DataTemplate)frame.Resources[name];
        }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var field = (InfoViewEntryField)item;
            var type = field.Type;
            if (field.IsEnum)
                return GetResource("enumEditorTemplate");
            if (field.ReferencedField != null)
                return GetResource("referenceEditorTemplate");
            if (type.Equals(typeof(DateTime)))
                return GetResource("dateEditorTemplate");
            if (type.Equals(typeof(bool)))
                return GetResource("boolEditorTemplate");
            if (type.Equals(typeof(double)))
                return GetResource("floatEditorTemplate");
            if (type.Equals(typeof(int)))
                return GetResource("intEditorTemplate");
            if (type.Equals(typeof(string)))
                return GetResource("textEditorTemplate");
            if (type.Equals(typeof(IImage)))
                return null;
            if (field.IsReadOnly)
                return GetResource("textEditorTemplate");

            System.Diagnostics.Debug.Assert(false);

            return null;
        }
    }

    public class InfoEntryFieldEnumItemConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter,
                              System.Globalization.CultureInfo culture)
        {
            var field = (InfoViewEntryField)parameter;
            return field.GetEnumItemByValue(value).Title;
        }

        public object ConvertBack(object value, Type targetType, object parameter,
                                  System.Globalization.CultureInfo culture)
        {
            var field = (InfoViewEntryField)parameter;
            string strVal = (string)value;
            if (string.IsNullOrEmpty(strVal))
                return null;
            return field.GetEnumItemByTitle(strVal).Value;
        }
    }

    public class Int32ToTextConverter : System.Windows.Data.IValueConverter
    {
        private Int32Converter converter;

        public Int32ToTextConverter()
        {
            converter = new Int32Converter();
        }

        public object Convert(object value, Type targetType, object parameter,
                              System.Globalization.CultureInfo culture)
        {
            return converter.ConvertToString(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter,
                                  System.Globalization.CultureInfo culture)
        {
            return converter.ConvertFromString((string)value);
        }
    }

    public class FloatToTextConverter : System.Windows.Data.IValueConverter
    {
        private DoubleConverter converter;

        public FloatToTextConverter()
        {
            converter = new DoubleConverter();
        }

        public object Convert(object value, Type targetType, object parameter,
                              System.Globalization.CultureInfo culture)
        {
            return converter.ConvertToString(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter,
                                  System.Globalization.CultureInfo culture)
        {
            return converter.ConvertFromString((string)value);
        }
    }
}
